#include <iostream>
using namespace std;
// const 变量只读，修饰常量
//静态数组定义时只能用常 量
//用const修饰的变量来进行定义
//编译的四个阶段 预处理 编译 汇编 链接
//非常量在运行阶段才计算出结果
//常量表达式在编译阶段出来结果，用于提高程序的执行效率
//不可以用constexpr来修饰结构体或者类的定义  但可以通过constexpr来修饰结构体或者类的对象

// const和constexpr的区别
//  constexpr 是 C++11 引入的，一方面是为了引入更多的编译时计算能力，
//提升效率，另一方面也是解决 C++98 的 const 的双重语义问题,这是一个遗留的命名问题，
// const语义上其实是只读（readonly)。
//  对于修饰Object来说：
// const并未区分出编译期常量和运行期常量
//  constexpr限定在了编译期常量
//  但是使用constexpr修饰的函数，返回值却不一定是编译期常量。
//  所以，对于constexpr需要两方面看待。
//  constexpr修饰的函数，简单的来说，
//  如果其传入的参数可以在编译时期计算出来，
//  那么这个函数就会产生编译时期的值。但是，
//  传入的参数如果不能在编译时期计算出来，
//  那么constexpr修饰的函数就和普通函数一样了。
//  不过，我们不必因此而写两个版本，
//  所以如果函数体适用于constexpr函数的条件，
//  可以尽量加上constexpr。
//  而检测constexpr函数是否产生编译时期值的方法很简单，
//  就是利用std::array需要编译期常值才能编译通过的小技巧。
//  这样的话，即可检测你所写的函数是否真的产生编译期常值了。
void func(const int num)
{
    int a1 = 520;
    int a2 = 250;
    const int count = 24;
    int array[count];
    // int array[a1];只能用常量来定义数组
    // int array[num];虽然传入的值也是用const修饰，
    //但是这不算常量，只是在函数func中不能修改其值
    array[0] = num;
    cout << array[0] << endl;
}
// constexpr void func1(){}  constexpr修饰的函数必须有返回值
// constexpr int func2(){int a =10;return a;}//返回值必须是常量 变量不行
//函数体定义必须在main前
//常量表达式函数内，不能出现常量表达式之外的语言

//错误例子
constexpr int func1()
{
    constexpr int a = 10;
    constexpr int b = 20;
    for (int i = 0; i < b; i++)
    {
        cout << "i = " << i << endl;
    }
    return a + b;
}
//正确例子
constexpr int func2()
{
    using mytype = int;
    constexpr mytype a = 100;
    constexpr mytype b = 20;
    constexpr mytype c = a * b;
    return c - (a + b);
}
//用constexpr修饰的模板函数会根据实际的参数传入情况判断该调用是否为常量表达式函数
struct Person
{
    const char *name;
    int age;
};
//定义函数模板
template <typename T>
constexpr T dispaly(T t)
{
    return t;
}
//由于返回值类型为定，所以实例化前无法判断是否为常来嗯表达式函数

//用于初始化构造函数
struct T
{
    constexpr T() : a(10)
    {
        // a =10; //初始化成员只能写在初始化列表里
        //在调用时无需对a进行赋值操作
    }
    int a;
};

int main()
{
    //会根据调用的情况不同而改变函数的性质
    Person p{"luffy", 19};
    Person p1 = dispaly(p); //传入参数为变量 普通函数
    //常量表达式
    constexpr int ret1 = dispaly(250);
    //常量函数表达式
    constexpr Person p2{"mike", 18};
    constexpr Person p3 = dispaly(p2);
    const int a = 10;
    func(a);
    return 0;
}